package org.hang.gift.service.impl;

import lombok.AllArgsConstructor;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.hang.exception.BusinessException;
import org.hang.exception.ResponseCode;
import org.hang.exception.RonghuaAssert;
import org.hang.gift.constants.GiftConstants;
import org.hang.gift.domain.GoodsSpu;
import org.hang.gift.domain.GoodsSpuViewLog;
import org.hang.gift.dtos.SpuOnsaleDto;
import org.hang.gift.mapper.GoodsSpuMapper;
import org.hang.gift.mapper.GoodsSpuViewLogMapper;
import org.hang.gift.service.IGoodsSpuService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.hang.gift.service.IGoodsSpuViewLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * spu表 服务实现类
 * @author hang
 * @since 2024-04-05
 */
@Service
public class GoodsSpuServiceImpl extends ServiceImpl<GoodsSpuMapper, GoodsSpu> implements IGoodsSpuService {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private GoodsSpuViewLogMapper goodsSpuViewLogMapper;

    /**
     * 礼物上架
     * @param ids
     * @return
     */
    @Override
    public String onSale(List<Long> ids) {
        // 1 参数校验
        // 1.1 参数非空校验,ids不能为空
        RonghuaAssert.isNotNull(ids, ResponseCode.RESPONSE_CODE_400015);
        // 1.2 校验要上架的商品的状态,只有审核通过的才可以上架
        // 只上架满足条件的,但是不满足条件的也要返回给前端让别人知道
        // 返回一个信息: 当前一共操作xx条数据,其中成功xx条,失败xx条(失败的具体的商品信息)
        // 1.2.1 根据ids查询到商品的具体信息
        List<GoodsSpu> goodsSpus = selectBatchIds(ids);
        // 1.2.2 筛选出其中状态为审核成功的
        goodsSpus =  goodsSpus.stream().filter(x -> x.getState()==1).collect(Collectors.toList());
        //如果goodsSpus为空，表示全部审核失败，不再往下执行，直接返回错误信息
        RonghuaAssert.isNotNull(goodsSpus,ResponseCode.RESPONSE_CODE_400016);
        //要返回给前端的信息
        String msg = "当前一共操作%s条数据,其中成功%s条,失败%s条";
        msg = String.format(msg,ids.size(),goodsSpus.size(),(ids.size() - goodsSpus.size()));

        //2,发送事务消息到rocketmq，事务消息中要包含满足条件的商品信息
        //2.1 首先将 要上架的从数据库中查出来的数据转换成 我们封装的dto类的数据
        List<SpuOnsaleDto> spuOnsaleDtos = new ArrayList<>();
        for (GoodsSpu spu : goodsSpus) {
            SpuOnsaleDto saleDto = new SpuOnsaleDto();
            saleDto.setId(spu.getId());
            saleDto.setCover(spu.getCover());
            saleDto.setName(spu.getGoodsName());
            saleDto.setTenantId(spu.getTenantId());
            saleDto.setTenantName(spu.getTenantName());
            saleDto.setOnsaleTime(new Date());
            saleDto.setTypeId(spu.getCategoryId());
            saleDto.setTypeName("口红");
            saleDto.setBrandId(spu.getBrandId());
            saleDto.setBrandName("香奈儿");
            // 无
            saleDto.setCommentCount(0);
            saleDto.setSaleCount(0);
            saleDto.setSkuProperties("");
            saleDto.setSkuProperties("");
            //最高价，最低价
            saleDto.setMaxPrice(spu.getHighPrice());
            saleDto.setMinPrice(spu.getLowPrice());
            //将数据一条条存入集合
            spuOnsaleDtos.add(saleDto);
        }
        //2.2 封装消息对象
        Message<List<SpuOnsaleDto>> message = MessageBuilder.withPayload(spuOnsaleDtos).build();
        //2.3为了防止跨服务进行查询，放入消息队列的数据不能只是商品的id,而是要存入es的 封装的dto类数据
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                GiftConstants.SPU_ONSALE_TX_PRODUCER_GROUP,
                GiftConstants.SPU_ONSALE_TX_TOPIC + ":" + GiftConstants.SPU_ONSALE_TX_TOPIC_TAG,
                message, null
        );
        // 如果发送消息失败,就说明上架失败,就返回一个错误信息
        if(sendResult.getSendStatus() != SendStatus.SEND_OK){
            throw new BusinessException("礼物上架失败!");
        }

        // 下面的3，4，5步为礼物微服务要进行的操作，也就是要在本地事务内完成
        // 3,修改数据库状态,添加上架时间 - 操作满足条件的
        // 4,添加上架的操作日志
        // 5,生成静态页面 - 详情页面

        // 6 将数据添加到es  -  搜索服务

        return msg;
    }

    /**
     * 礼物下架
     * @param ids
     * @return
     */
    @Override
    public String offSale(List<Long> ids) {
        // 1 参数校验
        // 1.1 参数非空校验,ids不能为空
        RonghuaAssert.isNotNull(ids, ResponseCode.RESPONSE_CODE_400017);
        // 返回一个信息: 当前一共操作xx条数据,其中成功xx条,失败xx条(失败的具体的商品信息)
        // 1.2.1 根据ids查询到商品的具体信息
        List<GoodsSpu> goodsSpus = selectBatchIds(ids);

        // 1.2.2 筛选出其中状态为上架成功的
        goodsSpus =  goodsSpus.stream().filter(x -> x.getState()==2).collect(Collectors.toList());

        //获取上架成功的礼物id
        List<Long> idList = goodsSpus.stream().map(GoodsSpu::getId).collect(Collectors.toList());
        //要返回给前端的信息
        String msg = "当前一共操作%s条数据,其中成功%s条,失败%s条";
        msg = String.format(msg,ids.size(),goodsSpus.size(),(ids.size() - goodsSpus.size()));

        //2,发送事务消息到rocketmq，
        //2.1 封装消息对象
        Message<List<Long>> message = MessageBuilder.withPayload(idList).build();
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                GiftConstants.SPU_OFFSALE_TX_PRODUCER_GROUP,
                GiftConstants.SPU_OFFSALE_TX_TOPIC + ":" + GiftConstants.SPU_OFFSALE_TX_TOPIC_TAG,
                message, null
        );
        // 如果发送消息失败,就说明下架失败,就返回一个错误信息
        if(sendResult.getSendStatus() != SendStatus.SEND_OK){
            throw new BusinessException("礼物下架失败!");
        }

        return msg;
    }

    /**
     * 礼物上架时执行本地事务
     * @param dtos
     */
    @Override
    @Transactional
    public void onsaleExecuteLocalTransaction(List<SpuOnsaleDto> dtos) {
        //1、获取要上架的礼物的id
        //遍历dtos集合，将id取出来封装成一个新的集合
        List<Long> ids = dtos.stream().map(SpuOnsaleDto::getId).collect(Collectors.toList());

        //2,修改数据库中礼物状态为上架,添加上架时间  先查询，再修改
        List<GoodsSpu> goodsSpus = selectBatchIds(ids);
        //遍历goodsSpus 集合，修改状态
        goodsSpus.forEach(x ->{
            x.setState(2);
            x.setOnsaleTime(new Date());
        });
        updateBatchById(goodsSpus);

        // 3 添加上架的操作日志
//        List<GoodsSpuViewLog> logs = new ArrayList<>();
//        for (GoodsSpu goodsSpu :goodsSpus) {
//            GoodsSpuViewLog viewLog = new GoodsSpuViewLog();
//            viewLog.setSpuId(goodsSpu.getId());
//            viewLog.setSpuName(goodsSpu.getGoodsName());
//            viewLog.setCreateTime(new Date());
//            viewLog.setTenantId(goodsSpu.getTenantId());
//            logs.add(viewLog);
//        }
//        goodsSpuViewLogMapper.batchinsert(logs);

        // 4 生成静态页面 - 详情页面
//        for (GoodsSpu goodsSpu : goodsSpus) {
//            VelocityUtils.staticByTemplate(goodsSpu,
//                    templatepath,
//                    outputpath+goodsSpu.getId()+".html");
//        }
    }




    /**
     * 礼物上架时回查本地事务
     * 如果商品的状态为上架，表示本地事务执行成功
     * @param dtos
     */
    @Override
    public Boolean onsaleCheckLocalTransaction(List<SpuOnsaleDto> dtos) {
        //1、获取要上架的礼物的id
        List<Long> ids = dtos.stream().map(SpuOnsaleDto::getId).collect(Collectors.toList());
        // 2 根据这些商品id查询信息
        List<GoodsSpu> goodsSpus = selectBatchIds(ids);
        //筛选出状态为上架的
        long count = goodsSpus.stream().filter(x -> x.getState() == 2).count();
        // 只要有1个商品的状态是上架,就说明本地事务执行成功
        return count > 0;
    }


    /**
     * 礼物下架时执行本地事务
     */
    @Override
    public void offsaleExecuteLocalTransaction(List<Long> idList) {
        //1、获取要下架的礼物的id集合
        //2,修改数据库中礼物状态为下架,添加下架时间  先查询，再修改
        List<GoodsSpu> goodsSpus = selectBatchIds(idList);
        //遍历goodsSpus 集合，修改状态
        goodsSpus.forEach(x ->{
            x.setState(3);
            x.setOffsaleTime(new Date());
        });
        updateBatchById(goodsSpus);

        // 3 添加下架的操作日志
//        List<GoodsSpuViewLog> logs = new ArrayList<>();
//        for (GoodsSpu goodsSpu :goodsSpus) {
//            GoodsSpuViewLog viewLog = new GoodsSpuViewLog();
//            viewLog.setSpuId(goodsSpu.getId());
//            viewLog.setSpuName(goodsSpu.getGoodsName());
//            viewLog.setCreateTime(new Date());
//            viewLog.setTenantId(goodsSpu.getTenantId());
//            logs.add(viewLog);
//        }
//        goodsSpuViewLogMapper.batchinsert(logs);
    }

    /**
     * 礼物下架时回查本地事务
     * 如果商品的状态为下架，表示本地事务执行成功
     */
    @Override
    public Boolean offsaleCheckLocalTransaction(List<Long> idList) {
        //1、获取要下架的礼物的id
        // 2 根据这些商品id查询信息
        List<GoodsSpu> goodsSpus = selectBatchIds(idList);
        //筛选出状态为下架的
        long count = goodsSpus.stream().filter(x -> x.getState() == 3).count();
        // 只要有1个商品的状态是下架,就说明本地事务执行成功
        return count > 0;
    }
}
